// Package middleware provides secure authentication middleware
package middleware

import (
	"log"
	"os"
	"time"

	"gitee.com/zhenyangze/gin-framework/internal/app/middleware/requests"
	jwt "github.com/appleboy/gin-jwt/v2"
	"github.com/gin-gonic/gin"
)

var (
	AuthMiddleware *jwt.GinJWTMiddleware
	err            error
)

var identityKey = "id"

// getJWTKey retrieves JWT key from environment with development fallback
func getJWTKey() []byte {
	secretKey := os.Getenv("JWT_SECRET_KEY")
	if secretKey == "" {
		// Check if running in production environment
		ginMode := os.Getenv("GIN_MODE")
		if ginMode == "release" {
			panic("JWT_SECRET_KEY environment variable must be set in production (GIN_MODE=release)")
		}
		
		// Development fallback: generate a warning and use default key
		log.Println("WARNING: JWT_SECRET_KEY not set. Using development default key.")
		log.Println("WARNING: This is NOT secure for production use!")
		log.Println("WARNING: Set JWT_SECRET_KEY environment variable for production.")
		
		// Use a default development key (32 bytes)
		secretKey = "development-jwt-secret-key-change-in-production"
	}
	return []byte(secretKey)
}

func init() {
	AuthMiddleware, err = jwt.New(&jwt.GinJWTMiddleware{
		Realm:       "gin-framework-secure",
		Key:         getJWTKey(), // Use secure key from environment
		Timeout:     15 * time.Minute, // Reduced from 1 hour
		MaxRefresh:  24 * time.Hour,   // Separate refresh token expiry
		IdentityKey: identityKey,
		PayloadFunc: func(data interface{}) jwt.MapClaims {
			if v, ok := data.(*requests.User); ok {
				return jwt.MapClaims{
					identityKey: v.UserName,
				}
			}
			return jwt.MapClaims{}
		},
		IdentityHandler: func(c *gin.Context) interface{} {
			claims := jwt.ExtractClaims(c)
			return &requests.User{
				UserName: claims[identityKey].(string),
			}
		},
		Authenticator: func(c *gin.Context) (interface{}, error) {
			var loginVals requests.Login
			if err := c.ShouldBind(&loginVals); err != nil {
				return "", jwt.ErrMissingLoginValues
			}

			// Input validation
			if len(loginVals.Username) < 3 || len(loginVals.Username) > 50 {
				return nil, jwt.ErrFailedAuthentication
			}
			if len(loginVals.Password) < 8 || len(loginVals.Password) > 128 {
				return nil, jwt.ErrFailedAuthentication
			}

			// TODO: Replace with secure authentication service
			// This is a temporary implementation - DO NOT USE IN PRODUCTION
			if loginVals.Username == "admin" && loginVals.Password == "SecureP@ssw0rd!" {
				return &requests.User{
					UserName:  loginVals.Username,
					LastName:  "System",
					FirstName: "Admin",
				}, nil
			}

			return nil, jwt.ErrFailedAuthentication
		},
		Authorizator: func(data interface{}, c *gin.Context) bool {
			if v, ok := data.(*requests.User); ok {
				// Check if user is active and has valid role
				// TODO: Implement proper role-based authorization
				return v.UserName != "" // Basic check - replace with role validation
			}
			return false
		},
		Unauthorized: func(c *gin.Context, code int, message string) {
			c.JSON(code, gin.H{
				"code":    code,
				"message": message,
			})
		},
		// Secure token lookup - only from Authorization header
		TokenLookup: "header:Authorization",

		// TokenHeadName is a string in the header. Default value is "Bearer"
		TokenHeadName: "Bearer",

		// TimeFunc provides the current time
		TimeFunc: time.Now,

		// Security enhancements
		SendCookie:     false,  // Disable cookie-based tokens for security
		SecureCookie:   true,   // Use secure cookies in production
		CookieHTTPOnly: true,   // Prevent XSS attacks
		CookieDomain:   "",     // Set appropriate domain in production
		CookieName:     "jwt",  // Cookie name if cookies are enabled
	})
}
